本篇要來介紹泛型,由於「泛型」在 TypeScript 中的內容蠻多的!!所以會拆成多篇來介紹
Day24 - Generics 泛型 X 泛型約束
再進入正題之前,先來回顧一下「陣列」設定型別的方式
🔗 文章傳送門:Day 06 - Array
let numbers: number[] = [1, 2, 3]; // number[] 表示一個數字型別陣列
let strings: string[] = ["hello", "TypeScript"]; // string[] 表示一個字串型別的陣列
除此之外,還有哪些定義方式呢?
那就是 陣列泛型(Array Generic)
可以使用陣列泛型 Array<元素型別>
來替換
let numbers: Array<number> = [1, 2, 3];
let strings: Array<string> = ["hello", "TypeScript"];
其實在前面的章節,早就有接觸過泛型了,只是沒有講到很深入而已
「泛型」是 TypeScript 中獨有的型別,它允許我們在函式、介面、Class,對相關參數的型別進行「參數化」。
這也代表我們可以透過「泛型」來建立一個更靈活的函式或其他類型的實體,用於多種數據類型而不失去型別安全性
你可以把泛型想成一個「萬用型」的工具 🔧🔧🔧
當你使用泛型時,不需要事先指定具體的型別,只需要在使用的時候指定型別即可,適用於任何你指定的數據類型
泛型會很常看到 T
,它是一個型別參數(Type Parameter
),可代進任意輸入的型別,此外,也可以自由命名,等等下面會再提到
泛型的基本語法是用「角括號」去包裹「型別參數」,如:<T>
function hello<T>(data: T) {
console.log(data);
};
hello<string>("Jack"); // ✅ 印出 Jack,data 參數型別會被代入為 string
hello<string>(123); // ❌ 型別錯誤
hello<number>(123) // ✅ 印出 123,data 參數型別會被代入為 number
上面的範例,函式 hello 後添加了 <T>
,用來代入任何型別,T
也可以叫做其它名字,例如 U
型別參數 T
的名稱可以自由取名。目前 T
已成一種約定成俗的慣例了,T 就是「Type」
T
- 用來表示一個通用的型別U
, V
, W
- 如果有多個型別參數,可使用這些字母來區分K
- Key,代表「鍵」的型別V
- Value,代表「值」的型別,常與K
一起用於物件中E
- Element,代表元素的型別R
- Return,代表回傳型別你也可以選擇更具體、特定的名字,例如:你正在處理使用者的相關資料,可以將參數命名為 <User>
看看下面的範例
函式 areItemsEqual
用於比較兩個物品是否相同,參數 <ItemType>
能夠更清楚表達它的用途和意義,有助於其他開發者更好理解和維護
function areItemsEqual<ItemType>(item1: ItemType, item2: ItemType): boolean {
return item1 === item2;
}
T
也可用在回傳值上喔~
function hello<T>(data: T): T {
return data;
};
上面有提到,如果有多個參數,可優先使用 U
, V
, W
這些字母來區分
本範例使用 <T, U>
// `T` 和 `U` 是型別參數,表示兩個不同的型別
function combine<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
// 👍🏻 推薦:可以使用型別推論寫法
const a = combine("world", 123);
console.log(a); // [world, 123]
// 也可以使用型別註釋
const b = combine<string, number>("world", 123);
console.log(b); // [world, 123]
// ❌ 故意出錯的型別註釋
const c = combine<string, string>("world", 123);
初學的人可能會被這函式奇異的樣貌給嚇到,在這個例子中
T
和 U
是型別參數,表示兩個不同的型別第一次接觸到泛型的時候,覺得它看起來不怎麼討喜XD 我可能有恐角括號症候群,心想為何要那麼多角括號和型別參數的代稱,一下 T 啊,一下 U 啊...
但慢慢的發現其實泛型有它的美好、彈性之處,雖然長得不好看(?
身為圖像人,來分享之前泛型的圖解
我們就以此範例程式碼為例子
function hello<T>(data: T) {
console.log(data);
};
hello<string>("Jack"); // ✅ 印出 Jack,data 參數型別會被代入為 string
hello<string>(123); // ❌ 型別錯誤
hello<number>(123) // ✅ 印出 123,data 參數型別會被代入為 number
繪製軟體:excalidraw
你會怎麼重構這段呢?
function processStringArray(strings: string[]): string[] {
return strings;
};
function processNumberArray(numbers: number[]): number[] {
return numbers;
};
let strAry = ["apple", "banana", "cherry"];
let numberAry = [1, 2, 3];
processStringArray(strAry)
processNumberArray(numberAry)
每天的內容有推到 github 上喔